﻿using NewsReader.Log;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace NewsReader.Helpers
{
    public enum SupportedSettings
    {
        RefreshFrequencyMinutes,
        DeleteItemsOlderThenDays,
        ParserEngine
    }

    public sealed class SettingsManager
    {
        private static readonly SettingsManager _instance = new SettingsManager();

        public static SettingsManager Instance
        {
            get { return _instance; }
        }

        private readonly Dictionary<SupportedSettings, object> _settings = new Dictionary<SupportedSettings, object>();


        public DateTimeOffset GetOldestDateOfArticleSupported()
        {
            var localDT = DateTime.Today.Subtract(TimeSpan.FromDays(GetValue<int>(SupportedSettings.DeleteItemsOlderThenDays)));
            localDT = DateTime.SpecifyKind(localDT, DateTimeKind.Local);
            return new DateTimeOffset(localDT);
        }

        private SettingsManager()
        {
            _settings.Add(SupportedSettings.RefreshFrequencyMinutes, 20);
            _settings.Add(SupportedSettings.DeleteItemsOlderThenDays, 10);
            _settings.Add(SupportedSettings.ParserEngine, "Readibility");
            UpdateSettingsFromDB();
        }

        private void UpdateSettingsFromDB()
        {
            var settings = PersistenceHelper.GetUserSettings();
            foreach (var setting in settings)
            {
                SupportedSettings sup;
                int intValue;
                if (Enum.TryParse(setting.Name, out sup))
                {
                    switch (sup)
                    {
                        case SupportedSettings.RefreshFrequencyMinutes:
                        case SupportedSettings.DeleteItemsOlderThenDays:
                            if (int.TryParse(setting.Value, out intValue))
                            {
                                _settings[sup] = intValue;
                            }
                            else
                            {
                                Logger.Log.WarnFormat("Failed to parse int value " + setting.Value);
                            }
                            break;
                        case SupportedSettings.ParserEngine:
                            _settings[sup] = setting.Value;
                            break;
                    }
                }
                else
                {
                    Logger.Log.WarnFormat("Failed to parse setting {0}", setting.Name);
                }
            }
        }

        public Task SaveSettingsAsync()
        {
            return Task.Factory.StartNew(() => SaveSettingsToDB());
        }

        public void SaveSettingsToDB()
        {
            var db = PersistenceHelper.GetUserDB();
            foreach (var kvp in _settings)
            {
                bool exists = db.ExecuteScalar<int>("select exists( select 1 from user_settings where name = ?)", kvp.Key.ToString("G")) == 1;

                if (exists)
                {
                    db.Execute("update user_settings set value = ? where name = ?", kvp.Value.ToString(), kvp.Key.ToString());
                }
                else
                {
                    db.Execute("insert into user_settings (name, value) values( ?, ? )", kvp.Key.ToString(), kvp.Value.ToString());
                }
            }
        }

        public T GetValue<T>(SupportedSettings setting, bool throwOnMissing = false)
        {
            object value;
            if (_settings.TryGetValue(setting, out value))
            {
                Debug.WriteLine("Getting value for setting {0}, value {1}", setting, value);
                if (value is T)
                    return (T)value;
                else
                    throw new ArgumentOutOfRangeException("Setting " + setting.ToString("G") + " is not a " + typeof(T).Name);
            }
            else if (throwOnMissing)
            {
                throw new ArgumentOutOfRangeException("Setting " + setting.ToString("G") + " does not exist.");
            }
            else
            {
                return default(T);
            }
        }

        public void SetValue(SupportedSettings setting, int value)
        {
            _settings[setting] = value;
        }

        public void SetValue(SupportedSettings setting, string value)
        {
            _settings[setting] = value;

            if (setting == SupportedSettings.ParserEngine)
            {
                ParserEngineChanged = true;
            }
        }

        public bool ParserEngineChanged { get; set; }
    }
}
